// jsencrypt 动态导入和 RSA 加密工具类
// RSA 加密工具类
export class RSAUtils {
  private static instance: RSAUtils
  private publicKey: string = ''
  private jsEncrypt: any = null
  private isLoaded: boolean = false

  private constructor() {
    // 构造函数，不在这里进行动态导入
    // 动态导入将在第一次使用时进行
  }

  public static getInstance(): RSAUtils {
    if (!RSAUtils.instance) {
      RSAUtils.instance = new RSAUtils()
    }
    return RSAUtils.instance
  }

  private async loadJSEncrypt() {
    if (!this.jsEncrypt && !this.isLoaded) {
      this.isLoaded = true // 标记为正在加载，避免重复加载
      try {
        // 动态导入 JSEncrypt
        const JSEncryptModule = await import('jsencrypt')
        this.jsEncrypt = new JSEncryptModule.JSEncrypt()
        console.log('JSEncrypt 库加载成功')
      } catch (error) {
        console.error('加载 JSEncrypt 失败:', error)
        this.isLoaded = false // 加载失败，重置标记
        throw new Error('RSA加密库加载失败: ' + error.message)
      }
    } else if (this.jsEncrypt) {
      // 如果已经加载，直接返回
      return
    }
    // 如果正在加载中，等待加载完成
    await new Promise(resolve => setTimeout(resolve, 100))
  }

  // 设置公钥
  public async setPublicKey(publicKey: string): Promise<void> {
    this.publicKey = this.formatPublicKey(publicKey)
    
    // 确保JSEncrypt库已加载
    if (!this.jsEncrypt) {
      await this.loadJSEncrypt()
    }
    
    if (this.jsEncrypt) {
      this.jsEncrypt.setPublicKey(this.publicKey)
    }
  }

  // 格式化公钥，移除 PEM 格式的头部和尾部
  private formatPublicKey(publicKey: string): string {
    if (!publicKey) return ''
    
    // 如果公钥包含 PEM 格式的头部和尾部，需要移除
    const formattedKey = publicKey
      .replace(/-----BEGIN PUBLIC KEY-----/g, '')
      .replace(/-----END PUBLIC KEY-----/g, '')
      .replace(/\s+/g, '')
    
    return formattedKey
  }

  // 加密文本
  public async encrypt(text: string): Promise<string> {
    if (!this.publicKey) {
      throw new Error('公钥未设置')
    }

    if (!this.jsEncrypt) {
      await this.loadJSEncrypt()
    }

    // 确保JSEncrypt库已正确加载
    if (!this.jsEncrypt) {
      throw new Error('RSA加密库未正确加载')
    }

    try {
      // 设置公钥到JSEncrypt实例
      this.jsEncrypt.setPublicKey(this.publicKey)
      
      const encrypted = this.jsEncrypt.encrypt(text)
      if (!encrypted) {
        console.error('RSA加密返回空结果，公钥:', this.publicKey)
        console.error('加密文本:', text)
        throw new Error('RSA加密失败: 加密结果为空')
      }
      return encrypted
    } catch (error) {
      console.error('RSA加密错误:', error)
      console.error('公钥:', this.publicKey)
      console.error('加密文本:', text)
      throw new Error('RSA加密失败: ' + error.message)
    }
  }

  // 检查 RSA 库是否已加载
  public isLibraryLoaded(): boolean {
    return !!this.jsEncrypt
  }

  // 检查是否已设置公钥
  public hasPublicKey(): boolean {
    return !!this.publicKey
  }

  // 获取当前公钥
  public getPublicKey(): string {
    return this.publicKey
  }
}

// 导出单例实例
export const rsaUtils = RSAUtils.getInstance()

// 便捷的加密函数
export const encryptWithRSA = async (text: string, publicKey?: string): Promise<string> => {
  if (publicKey) {
    await rsaUtils.setPublicKey(publicKey)
  }
  return rsaUtils.encrypt(text)
}